home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmiSoft / Util / Arc / Checkx.lha / CheckX / sources / CheckX.c next >
C/C++ Source or Header  |  2002-12-30  |  59KB  |  1,928 lines

  1. #define NAME         "CheckX"
  2. #define REVISION     "92"
  3. #define DISTRIBUTION "(Freeware) "
  4. #define DATE         "30.12.2002"
  5. #define VERSION      "1"
  6. #define AUTHOR       "by Dirk Stöcker <stoecker@epost.de>"
  7.  
  8. /*
  9. This program scans for crunched, linked files and archived files. It
  10. decrunches them and saves the result files to another directory-tree.
  11. The scanning routines are recursive and thus check really all stuff.
  12.  
  13. The program must be compiled and linked without startup-code. You can set
  14. the pure file protection bit and make it resident, because it is multi-
  15. reentrant (no global variables, except library bases).
  16. */
  17.  
  18. /* Programmheader
  19.  
  20.     Name:        CheckX
  21.     Author:        SDI
  22.     Distribution:    Freeware
  23.     Description:    scans, decrunches and dearchives files
  24.     Compileropts:    -
  25.     Linkeropts:    -l xfdmaster xpkmaster xadmaster amiga -gsi
  26.  
  27.  1.0   14.12.96 : first Version
  28.  1.1   28.12.96 : moved PassRequest into xpkmaster.library
  29.  1.2   12.02.97 : now also decrunches Exe-Files
  30.  1.3   15.06.97 : added length output as test
  31.  1.4   21.11.97 : renamed from Decrunch, got really new program
  32.  1.5   22.11.97 : bug-fixes
  33.  1.6   29.11.97 : added unarchiving feature
  34.  1.7   30.11.97 : bug-fixes
  35.  1.8   06.12.97 : xpkmaster.library now only required with ASKPWD option
  36.  1.9   07.12.97 : Added archive copy for weird archive names, better error
  37.     codes
  38.  1.10  08.12.97 : fixed error codes a bit
  39.  1.11  11.12.97 : disabled DOS requests, added Zip-Archives, added TaskID
  40.     to temporary filenames
  41.  1.12  12.12.97 : added Arc, ZOO and LhASFX archives
  42.  1.13  13.12.97 : fixed Arc recognition
  43.  1.14  19.12.97 : deletes copied arc before scan
  44.  1.15  22.12.97 : crunched archives are unarchived correctly now
  45.  1.16  02.01.98 : opens dos.library itself, no startup-code required
  46.  1.17  23.01.98 : added disk crunchers
  47.  1.18  24.01.98 : some fixes
  48.  1.19  01.02.98 : little bug-fix in argument-option use
  49.  1.20  06.02.98 : better error output, added automount
  50.  1.21  08.02.98 : little bug-fix
  51.  1.22  10.02.98 : fixed archive copy conditions, added PRINTALL
  52.  1.23  12.02.98 : fixed help text, bug fixes with unlinking and FreeMem
  53.  1.24  13.02.98 : added unstripping
  54.  1.25  04.03.98 : added PRINTEXEC
  55.  1.26  13.03.98 : added high density DMS support
  56.  1.27  19.03.98 : added LOUD keyword
  57.  1.28  23.03.98 : RDx no longer depends on archive depth, but on dddepth
  58.  1.29  10.04.98 : bug fixes
  59.  1.30  26.04.98 : bug fixes
  60.  1.31  09.05.98 : now uses no longer adress 4 for SysBase
  61.  1.32  31.05.98 : better output
  62.  1.33  04.06.98 : added HEADER addition for address files
  63.  1.34  08.08.98 : bug fix with SAVE
  64.  1.35  24.09.98 : added xvs.library virus checks
  65.  1.36  18.10.98 : xvs is opened global and only once
  66.  1.37  30.10.98 : renamed from CheckXFD
  67.  1.38  11.11.98 : fixed format drive bug using a delay and an error report
  68.  1.39  14.11.98 : format error with AUTOMOUNT removed
  69.  1.40  16.11.98 : removed HEADER addition stuff
  70.  1.41  18.11.98 : better RDx: access and mount
  71.  1.42  23.11.98 : fixed bug with hunk stripping
  72.  1.43  29.12.98 : now prints an error, when virus detection is turned off,
  73.     added time calculation and output
  74.  1.44  31.12.98 : little bug fix
  75.  1.45  06.02.99 : bug fixes, added xadmaster.library stuff, removed LOUD
  76.     and internal DMS call
  77.  1.46  09.02.99 : removed internal LZX call
  78.  1.47  11.02.99 : now uses assembler startcode allocating a bigger stack
  79.  1.48  14.02.99 : bug-fixes for nocylinder archivers (PackDev)
  80.  1.49  16.02.99 : fixed strip option (don't know, where the error was :-)
  81.  1.50  21.02.99 : removed internal Zoom call and disk-archiver stuff
  82.  1.51  22.02.99 : fixed archiver call for remaining non-XAD archivers, added
  83.     empty file check
  84.  1.52  23.02.99 : fixed StartCode return value
  85.  1.53  24.02.99 : forgot empty check for archived files
  86.  1.54  08.03.99 : old archiver calling did not work, when file was XAD
  87.     unarchived
  88.  1.55  26.03.99 : prints error, when logfile cannot be created
  89.  1.56  30.03.99 : added bootblock scanning for unarchived disks
  90.  1.57  16.05.99 : bug fix with unlinked file save
  91.  1.58  17.07.99 : removed internal LhA Support
  92.  1.59  30.07.99 : bug fix with file name prints
  93.  1.60  03.08.99 : added DEBUG option
  94.  1.61  05.08.99 : added XVS SelfTest and MemoryTest
  95.  1.62  19.08.99 : added error summary, again fixed name problem
  96.  1.63  14.09.99 : solved big memory loss problem (did not free xadArchiveInfo),
  97.     added logfile comment
  98.  1.64  17.10.99 : removed external archiver calls, added QUIET
  99.  1.65  24.11.99 : now sets nice return values
  100.  1.66  26.11.99 : tries reading again before giving read error
  101.  1.67  03.12.99 : bug fix in name printing
  102.  1.68  04.12.99 : tries again opening files.
  103.  1.69  16.12.99 : added NOSILENT Option
  104.  1.70  15.01.00 : files from disc archives are extracted directly now,
  105.     removed double read tries
  106.  1.71  16.01.00 : fixed error messages for disk unarchiving
  107.  1.72  12.02.00 : added support for ADF images
  108.  1.73  13.02.00 : bug fix for disk archives
  109.  1.74  09.03.00 : now detects XADFIF_NOFILENAME and XADFIF_NOUNCRUNCHSIZE
  110.  1.75  05.04.00 : fixed bug with XADFIF_NOFILENAME
  111.  1.76  26.04.00 : added size checkout for XADFIF_NOUNCRUNCHSIZE
  112.  1.77  05.06.00 : added support for multiple filesystems, removed NODOS and
  113.     diskerr errors, always prints FS-type now.
  114.  1.78  24.07.00 : bug fix
  115.  1.79  27.07.00 : bug fix with multi FS support
  116.  1.80  14.09.00 : added SAVEALL keyword
  117.  1.81  25.03.01 : added support for crypted archives and large archive scan
  118.  1.82  05.04.01 : fixed Enforcer hit
  119.  1.83  08.04.01 : empty file got warning
  120.  1.84  18.04.01 : added texts in case libraries could not be opened
  121.  1.85  12.07.01 : added sector checks, reduced final file size
  122.  1.86  30.09.01 : sector check is default now, bug fixes
  123.  1.87  27.01.02 : added CRC calculation and DEEPNAME option
  124.  1.88  31.08.02 : added ASKPWD for disk archives
  125.  1.89  06.10.02 : workaround for file 42.zip
  126.  1.90  20.11.02 : fixed CRC problem
  127.  1.91  29.12.02 : readded bootblock virus detection after XVS changed in this
  128.     point.
  129.  1.92  30.12.02 : Last version produced to many wrong virus hits, fixed
  130. */
  131.  
  132. #include <proto/exec.h>
  133. #include <proto/dos.h>
  134. #include <proto/xfdmaster.h>
  135. #include <proto/xadmaster.h>
  136. #include <proto/xpkmaster.h>
  137. #include <proto/intuition.h>
  138. #include <proto/xvs.h>
  139. #include <proto/utility.h>
  140. #include <libraries/xfdmaster.h>
  141. #include <dos/dostags.h>
  142. #include <dos/doshunks.h>
  143. #include <dos/filehandler.h>
  144. #include <exec/memory.h>
  145. #include "SDI_compiler.h"
  146.  
  147. #define PARAM   "FROM,LOG,SAVE/K,ALL/S,ASKPWD/S,PRINTALL/S,PRINTEXEC/S," \
  148.         "NODECRUNCH/S,NOUNLINK/S,NOUNARCHIVE/S,NOUNTRACK/S,"     \
  149.         "NOSECTOR/S,NOSILENT/S,NOSTRIP/S,NOVIRUS/S,"         \
  150.         "DEBUG/S,QUIET/S,SAVEALL/S,CRC/S,DEEPNAME/S"
  151.  
  152. #define version "$VER: " NAME " " VERSION "." REVISION " (" DATE ") " DISTRIBUTION AUTHOR
  153.  
  154. void RawPutChar(ULONG c);
  155.  
  156. #ifdef __SASC
  157.   #pragma libcall SysBase RawPutChar 204 001
  158. #elif defined(__GNUC__)
  159.   #define RawPutChar(c) LP1NR(204, RawPutChar, ULONG, c, d0, , SysBase)
  160. #else
  161.   #pragma amicall(SysBase,0x204,RawPutChar(d0))
  162. #endif
  163.  
  164. #define PASSWORDSIZE 100
  165.  
  166. struct FileData {
  167.   struct CrunchMemList * fd_MemList;      /* list of all memory allocations */
  168. #ifdef __SASC
  169.   struct xfdMasterBase * fd_xfdMasterBase;
  170.   struct Library *     fd_xvsBase;
  171.   struct xadMasterBase * fd_xadMasterBase;
  172.   struct DosLibrary *     fd_DOSBase;
  173.   struct ExecBase *     fd_SysBase;
  174. #endif
  175.   ULONG *         fd_CRCBuf;       /* the CRC table */
  176.   STRPTR         fd_Name;         /* the file name */
  177.   STRPTR                 fd_Memory;       /* for bootblock checks */
  178.   BPTR           fd_LogFileFH;    /* FileHandle of log file */
  179.   BPTR             fd_ArcFileFH;    /* FileHandle in case of large archive */
  180.   ULONG           fd_SaveDirL;     /* Lock to save directory */
  181.   ULONG             fd_Flags;        /* the argument and status flags */
  182.   ULONG             fd_NumVirus;     /* total number of viruses */
  183.   ULONG                  fd_NumSectors;   /* total number of currupted sectors */
  184.   ULONG             fd_CHKXErrors;   /* total number of CheckX errors */
  185.   ULONG                  fd_CHKXWarnings; /* total number of CheckX warnings - not printed yet */
  186.   ULONG             fd_XFDErrors;    /* total number of XFD errors */
  187.   ULONG             fd_XADErrors;    /* total number of XAD errors */
  188.   ULONG             fd_CorruptedArchives; /* total number of corrupted archives */
  189.   ULONG                  fd_CRC32;        /* the CRC of current buffer */
  190.   UBYTE           fd_RecurseDepth; /* depth of recursion */
  191.   UBYTE           fd_LinkNum;      /* number of unlinked part */
  192.   UBYTE                  fd_Password[PASSWORDSIZE];/* the last allocated passwort */
  193. };
  194.  
  195. typedef struct xadMasterBase XADMASTERBASE;
  196. typedef struct xfdMasterBase XFDMASTERBASE;
  197. typedef struct Library XVSBASE;
  198.  
  199. #ifdef __SASC
  200.   static struct ExecBase *sysbase;
  201.   #define XpkBase    xpkbase
  202.   #define ASSIGN_XPK
  203.   #define IntuitionBase    intuitionbase
  204.   #define ASSIGN_INT
  205.   #define UtilityBase    utilitybase
  206.   #define ASSIGN_UTIL
  207.   #define xfdMasterBase    fd->fd_xfdMasterBase
  208.   #define ASSIGN_SYS    sysbase = fd->fd_SysBase = (*((struct ExecBase **) 4));
  209.   #define SysBase       fd->fd_SysBase
  210.   #define DOSBase       fd->fd_DOSBase
  211.   #define ASSIGN_DOS    DOSBase = dosbase;
  212.   #define xvsBase    fd->fd_xvsBase
  213.   #define xadMasterBase    fd->fd_xadMasterBase
  214. #else
  215.   struct Library *     XpkBase;
  216.   struct IntuitionBase * IntuitionBase;
  217.   struct UtilityBase *   UtilityBase;
  218.   #define ASSIGN_XPK     XpkBase        = xpkbase;
  219.   #define ASSIGN_INT     IntuitionBase  = intuitionbase;
  220.   #define ASSIGN_UTIL     UtilityBase    = utilitybase;
  221.   #define ASSIGN_SYS     SysBase        = (*((struct ExecBase **) 4));
  222.   #define ASSIGN_DOS     DOSBase        = dosbase;
  223.   struct xfdMasterBase * xfdMasterBase;
  224.   struct Library *     xvsBase;
  225.   struct xadMasterBase * xadMasterBase;
  226.   struct DosLibrary *     DOSBase;
  227.   struct ExecBase *     SysBase;
  228. #endif
  229.  
  230. struct Args {
  231.   STRPTR from;
  232.   STRPTR log;
  233.   STRPTR save;
  234.   ULONG  all;
  235.   ULONG  askpwd;
  236.   ULONG  printall;
  237.   ULONG  printexec;
  238.   ULONG  nodecrunch;
  239.   ULONG  nounlink;
  240.   ULONG  nounarchive;
  241.   ULONG  nountrack;
  242.   ULONG  nosector;
  243.   ULONG  nosilent;
  244.   ULONG  nostrip;
  245.   ULONG  novirus;
  246.   ULONG  debug;
  247.   ULONG     quiet;
  248.   ULONG  saveall;
  249.   ULONG  crc;
  250.   ULONG  deepname;
  251. };
  252.  
  253. struct CrunchMemList {
  254.   struct CrunchMemList * cml_Next;
  255.   APTR             cml_MemoryRegion;
  256.   ULONG             cml_MemorySize;
  257. };
  258.  
  259. #define CHECKXFLAG_SAVE            (1<< 0)
  260. #define CHECKXFLAG_ALL            (1<< 1)
  261. #define CHECKXFLAG_ASKPWD        (1<< 2)
  262. #define CHECKXFLAG_PRINTALL        (1<< 3)
  263. #define CHECKXFLAG_PRINTEXEC        (1<< 4)
  264. #define CHECKXFLAG_NODECRUNCH        (1<< 5)
  265. #define CHECKXFLAG_NOSECTOR        (1<< 6)
  266. #define CHECKXFLAG_NOUNLINK        (1<< 7)
  267. #define CHECKXFLAG_NOUNARCHIVE        (1<< 8)
  268. #define CHECKXFLAG_NOUNTRACK        (1<< 9)
  269. #define CHECKXFLAG_NOSTRIP        (1<<10)
  270. #define CHECKXFLAG_DEBUG        (1<<11)
  271. #define CHECKXFLAG_QUIET        (1<<12)
  272. #define CHECKXFLAG_SAVEALL        (1<<13)
  273. #define CHECKXFLAG_CRC            (1<<14)
  274. #define CHECKXFLAG_DEEPNAME        (1<<15)
  275.  
  276. #define CHECKXFLAG_XVSLIB        (1<<20)
  277.  
  278. #define CHKXCALLFLAGS    (CHECKXFLAG_SAVE|CHECKXFLAG_ALL|        \
  279.              CHECKXFLAG_ASKPWD|CHECKXFLAG_PRINTALL|        \
  280.              CHECKXFLAG_PRINTEXEC|CHECKXFLAG_NODECRUNCH|    \
  281.              CHECKXFLAG_NOUNLINK|CHECKXFLAG_NOUNARCHIVE|    \
  282.              CHECKXFLAG_NOUNTRACK|CHECKXFLAG_NOSTRIP|    \
  283.              CHECKXFLAG_DEBUG|CHECKXFLAG_QUIET|        \
  284.              CHECKXFLAG_XVSLIB|CHECKXFLAG_SAVEALL|        \
  285.              CHECKXFLAG_NOSECTOR|CHECKXFLAG_CRC|        \
  286.              CHECKXFLAG_DEEPNAME)
  287.  
  288. #define CHKXSAVEFLAGS    (CHECKXFLAG_LINKED|CHECKXFLAG_CRUNCHED|        \
  289.              CHECKXFLAG_STRIPPED|CHECKXFLAG_SAVEALL)
  290.  
  291. #define CHKXNAMEFLAGS    (CHECKXFLAG_NAMEPRINTED|CHECKXFLAG_CRCVALID|    \
  292.              CHECKXFLAG_SHORTNAME)
  293.  
  294. #define CHECKXFLAG_MASTERTEXT        (1<<22) /* texts unrelated to files */
  295. #define CHECKXFLAG_SHORTNAME        (1<<23)
  296. #define CHECKXFLAG_CRCVALID        (1<<24)
  297. #define CHECKXFLAG_BBEXTRACTED        (1<<25)
  298. #define CHECKXFLAG_NAMEPRINTED        (1<<26)
  299. #define CHECKXFLAG_CRUNCHED        (1<<27)
  300. #define CHECKXFLAG_LINKED        (1<<28)
  301. #define CHECKXFLAG_ADDRESS        (1<<29)
  302. #define CHECKXFLAG_NOFREEMEM        (1<<30)
  303. #define CHECKXFLAG_STRIPPED        (1<<31)
  304.  
  305. #define CHXWARN_OFFSET        30
  306. #define XADERR_OFFSET        0x100
  307. #define XFDERR_OFFSET        0x200
  308.  
  309. #define CHKXERR_NOMEMORY    1
  310. #define CHKXERR_EXAMINEERR    2
  311. #define CHKXERR_OPENERR        3
  312. #define CHKXERR_READ        4
  313. #define CHKXERR_SCANERR        5
  314. #define CHKXERR_BREAK        6
  315. #define CHKXERR_OPENDIR        7
  316. #define CHKXERR_RESOURCE    8
  317. #define CHKXERR_NOBOOTVIRUS    9
  318. #define CHKXERR_WRITE        10
  319. #define CHKXERR_NOVIRUS        11
  320. #define CHKXERR_NOMEMORYARC    12
  321. #define CHKXERR_NOSECTOR        13
  322.  
  323. #define CHKXWARN_NOVIRUS    31
  324. #define CHKXWARN_XVSSELFTEST    32
  325. #define    CHKXWARN_MEMVIRUS    33
  326. #define CHKXWARN_EMPTY        34
  327.  
  328. static void SetLogComment(struct FileData *, STRPTR);
  329. static LONG DoDirectoryScan(struct FileData *, STRPTR, STRPTR);
  330. static LONG DoFileOpen(struct FileData *);
  331. static LONG DoGetVirus(struct FileData *, APTR, ULONG);
  332. static LONG DoFileUnArchive(struct FileData *, APTR, ULONG);
  333. static LONG DoFileUnLink(struct FileData *, APTR, ULONG);
  334. static LONG DoFileUnCrunch(struct FileData *, APTR, ULONG);
  335. static LONG DoFileStrip(struct FileData *, APTR, ULONG);
  336. static void PrintCHKXFile(struct FileData *);
  337. static void PrintCHKXErr(struct FileData *, LONG);
  338. static void PrintCHKXTxt(struct FileData *, STRPTR, ...);
  339. static LONG AddCrunchMemList(struct FileData *, APTR, ULONG);
  340. static void FreeCrunchMemList(struct FileData *, APTR);
  341. static LONG SaveUncrFile(struct FileData *, APTR, ULONG);
  342. static ULONG OpenParentDir(struct FileData *);
  343. static ULONG OpenNewDir(struct FileData *, STRPTR);
  344. static LONG DoSectorCheck(struct FileData *, APTR, ULONG, ULONG);
  345. static void clear(STRPTR, ULONG);
  346. static void SPrintF(struct FileData *, STRPTR buf, STRPTR format, ...);
  347. static ASM(void) KPutC(REG(d0, ULONG c), REG(a3, struct FileData *));
  348. static void KPrintf(struct FileData *, STRPTR fmt, ...);
  349. static ASM(LONG) BreakHookCheckX(void);
  350.  
  351. static const struct Hook breakhook = {{0,0},(ULONG (*)()) BreakHookCheckX, 0};
  352.  
  353. /* All memory regions must be in mem list. All unneeded memory must be freed
  354.    as fast as possible (after unlinking, decrunching), as well as the
  355.    MemoryList structure.
  356.    
  357.    The program has a loop like scan routine system, which is called for
  358.    every file:
  359.  
  360.    A) Scan files, directories and sub directories and call following for
  361.       every file:
  362.    1) Check for viruses.
  363.    2) Test if it is an archive. When yes decrunch and start for every file
  364.       with point 1.
  365.    3) Test if file is linked. When yes unlink and call point 1 for both
  366.       parts.
  367.    4) Test if file is crunched. When yes, decrunch and start again with
  368.       point 1.
  369.    5) Try stripping useless stuff. When successful start with point 1 again.
  370.    6) Possibly save file (with SAVE option) or end loop here.
  371. */
  372.  
  373. /* main routine, do argument parsing */
  374. LONG start(void)
  375. {
  376.   LONG error = RETURN_FAIL;
  377.   struct FileData fd[1];
  378.   struct DosLibrary *dosbase;
  379.   struct Process *task;
  380.  
  381.   clear((STRPTR)fd, sizeof(struct FileData));
  382.   ASSIGN_SYS
  383.  
  384.   /* test for WB and reply startup-message */
  385.   if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  386.   {
  387.     WaitPort(&task->pr_MsgPort);
  388.     Forbid();
  389.     ReplyMsg(GetMsg(&task->pr_MsgPort));
  390.     return RETURN_FAIL;
  391.   }
  392.  
  393.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  394.   {
  395.     XFDMASTERBASE * xfdmasterbase;
  396.  
  397.     ASSIGN_DOS
  398.     if((xfdmasterbase = (XFDMASTERBASE *) OpenLibrary("xfdmaster.library", 39)))
  399.     {
  400.       XADMASTERBASE *xadmasterbase;
  401.  
  402.       xfdMasterBase = xfdmasterbase;
  403.       if((xadmasterbase = (XADMASTERBASE *) OpenLibrary("xadmaster.library", 10)))
  404.       {
  405.         struct Args Args;
  406.         struct RDArgs *rda;
  407.  
  408.     xadMasterBase = xadmasterbase;
  409.         clear((STRPTR)(&Args), sizeof(struct Args));
  410.  
  411.         if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  412.         {
  413.           rda->RDA_ExtHelp = version; /* is removed by optimizer */
  414.           rda->RDA_ExtHelp =
  415.           "FROM        source file or directory - may contain patterns\n"
  416.           "LOG         log file name\n"
  417.           "SAVE        directory, where decrunched files are saved\n"
  418.           "ALL         scan deep into directories\n"
  419.           "ASKPWD      ask for password when needed (needs xpkmaster.library)\n"
  420.       "PRINTALL    print all filenames\n"
  421.           "PRINTEXEC   print names of all executable files\n"
  422.           "NODECRUNCH  do not decrunch files with xfdmaster\n"
  423.           "NOUNLINK    do not unlink files with xfdmaster\n"
  424.           "NOUNARCHIVE do not unarchive file archives with xadmaster\n"
  425.           "NOUNTRACK   do not unarchive track archives with xadmaster\n"
  426.           "NOSECTOR    do not check the files for virus infected sectors\n"
  427.           "NOSILENT    do not disable dos requests\n"
  428.           "NOSTRIP     do not strip useless hunks\n"
  429.           "NOVIRUS     do not scan with xvs.library for viruses\n"
  430.           "DEBUG       also output texts to serial debug engine\n"
  431.           "QUIET       do not output texts to console\n"
  432.           "SAVEALL     saves all files (also uncrunched) except address files\n"
  433.           "CRC         print CRC32 in fornt of each filename\n"
  434.           "DEEPNAME    print own name for every part (e.g. unliked parts)\n";
  435.  
  436.           if(ReadArgs(PARAM, (LONG *) &Args, rda))
  437.           {
  438.             ULONG flags = 0, log = 0;
  439.             XVSBASE *xvsbase = 0;
  440.  
  441.             if(!Args.from)        Args.from = "#?";
  442.             if(Args.all)        flags |= CHECKXFLAG_ALL;
  443.             if(Args.save)        flags |= CHECKXFLAG_SAVE;
  444.             if(Args.saveall)        flags |= CHECKXFLAG_SAVEALL;
  445.             if(Args.askpwd)        flags |= CHECKXFLAG_ASKPWD;
  446.         if(Args.printall)        flags |= CHECKXFLAG_PRINTALL;
  447.         if(Args.printexec)        flags |= CHECKXFLAG_PRINTEXEC;
  448.             if(Args.nodecrunch)        flags |= CHECKXFLAG_NODECRUNCH;
  449.             if(Args.nounlink)         flags |= CHECKXFLAG_NOUNLINK;
  450.             if(Args.nounarchive)    flags |= CHECKXFLAG_NOUNARCHIVE;
  451.             if(Args.nountrack)        flags |= CHECKXFLAG_NOUNTRACK;
  452.             if(Args.nostrip)        flags |= CHECKXFLAG_NOSTRIP;
  453.             if(Args.debug)        flags |= CHECKXFLAG_DEBUG;
  454.             if(Args.quiet)        flags |= CHECKXFLAG_QUIET;
  455.             if(Args.nosector)        flags |= CHECKXFLAG_NOSECTOR;
  456.             if(Args.deepname)           flags |= CHECKXFLAG_DEEPNAME;
  457.             /*if(Args.crc)*/
  458.             {
  459.               if((fd->fd_CRCBuf = (ULONG *) AllocMem(4*256, MEMF_ANY)))
  460.               {
  461.                 ULONG i, j, k;
  462.                 if(Args.crc)
  463.                   flags |= CHECKXFLAG_CRC;
  464.  
  465.                 for(i = 0; i < 256; ++i)
  466.                 {
  467.                   k = i;
  468.                   for(j = 0; j < 8; ++j)
  469.                   {
  470.                     if(k & 1)
  471.                       k = (k >> 1) ^ 0xEDB88320;
  472.                     else
  473.                       k >>= 1;
  474.                   }
  475.                   fd->fd_CRCBuf[i] = k;
  476.                 }
  477.               }
  478.             }
  479.  
  480.             if(!Args.novirus)
  481.             {
  482.               if((xvsbase = (XVSBASE *) OpenLibrary("xvs.library", 33)))
  483.               {
  484.                 flags |= CHECKXFLAG_XVSLIB;
  485.                 xvsBase = xvsbase;
  486.               }
  487.         }
  488.  
  489.             if(!Args.log || (log = Open(Args.log, MODE_READWRITE)))
  490.             {
  491.           APTR win;
  492.           ULONG s1 = 0, s2 = 0, msecs;
  493.           struct IntuitionBase *intuitionbase;
  494.  
  495.           win = task->pr_WindowPtr;
  496.           if(!Args.nosilent)
  497.             task->pr_WindowPtr = (APTR) -1;
  498.           /* prevent dos requests */
  499.  
  500.           if(log)
  501.           {
  502.             SetFileSize(log, 0, OFFSET_BEGINNING);
  503.             SetProtection(Args.log, FIBF_EXECUTE);
  504.             SetLogComment(fd, Args.log);
  505.           }
  506.  
  507.               fd->fd_Flags = flags | CHECKXFLAG_MASTERTEXT;
  508.               fd->fd_LogFileFH = log;
  509.  
  510.           if(!xvsbase)
  511.             PrintCHKXErr(fd, CHKXWARN_NOVIRUS);
  512.           else
  513.           {
  514.                 struct xvsMemoryInfo *mi;
  515.  
  516.             if(!xvsSelfTest())
  517.               PrintCHKXErr(fd, CHKXWARN_XVSSELFTEST);
  518.  
  519.                   if((mi = (struct xvsMemoryInfo *) xvsAllocObject(XVSOBJ_MEMORYINFO)))
  520.                   { 
  521.                     if(xvsSurveyMemory(mi))
  522.                 PrintCHKXErr(fd, CHKXWARN_MEMVIRUS);
  523.  
  524.                     xvsFreeObject(mi);
  525.                   }
  526.           }
  527.  
  528.           if((intuitionbase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
  529.           {
  530.             ASSIGN_INT
  531.             CurrentTime(&s1, &msecs);
  532.           }    
  533.  
  534.           ++fd->fd_RecurseDepth;
  535.               fd->fd_Flags &= ~(CHECKXFLAG_MASTERTEXT);
  536.           error = DoDirectoryScan(fd, Args.from, Args.save);
  537.           --fd->fd_RecurseDepth;
  538.               fd->fd_Flags = flags | CHECKXFLAG_MASTERTEXT;
  539.  
  540.               if(error)
  541.               {
  542.                 PrintCHKXErr(fd, error);
  543.                 error = RETURN_FAIL;
  544.               }
  545.  
  546.           task->pr_WindowPtr = win;
  547.  
  548.           if(intuitionbase)
  549.           {
  550.             CurrentTime(&s2, &msecs);
  551.             s2 -= s1;
  552.             s1 = s2 / 60;
  553.             s2 %= 60;
  554.             msecs = s1 / 60;
  555.             s1 %= 60;
  556.             PrintCHKXTxt(fd, "\nTime needed for check: %2ld:%02ld:%02ld", msecs, s1, s2);
  557.             CloseLibrary((struct Library *) intuitionbase);
  558.           }
  559.           if(fd->fd_NumVirus && !fd->fd_NumSectors)
  560.             PrintCHKXTxt(fd, "The scan detected %ld virus%s.", fd->fd_NumVirus, fd->fd_NumVirus > 1 ? "es" : "");
  561.           else if(fd->fd_NumVirus && fd->fd_NumSectors)
  562.             PrintCHKXTxt(fd, "The scan detected %ld virus%s and %ld defective sector%s.", fd->fd_NumVirus,
  563.             fd->fd_NumVirus > 1 ? "es" : "", fd->fd_NumSectors, fd->fd_NumSectors > 1 ? "s" : "");
  564.           else if(!fd->fd_NumVirus && fd->fd_NumSectors)
  565.             PrintCHKXTxt(fd, "The scan detected %ld defective sector%s.", fd->fd_NumSectors,
  566.             fd->fd_NumSectors > 1 ? "s" : "");
  567.           if(fd->fd_CHKXErrors || fd->fd_XADErrors || fd->fd_XFDErrors || fd->fd_CorruptedArchives)
  568.             PrintCHKXTxt(fd, "There were errors (CheckX/XFD/XAD/corrupted archives): %ld/%ld/%ld/%ld.",
  569.             fd->fd_CHKXErrors, fd->fd_XFDErrors, fd->fd_XADErrors, fd->fd_CorruptedArchives);
  570.           if(!error && (fd->fd_NumVirus || !xvsBase))
  571.           {
  572.             SetIoErr(0);
  573.             error = RETURN_WARN;
  574.           }
  575.  
  576.               if(log)
  577.                 Close(log);
  578.             }
  579.             else if(Args.log && !Args.quiet)
  580.               Printf("Could not create logfile.\n");
  581.  
  582.         if(xvsbase)
  583.           CloseLibrary((struct Library *) xvsbase);
  584.         if(fd->fd_CRCBuf)
  585.           FreeMem(fd->fd_CRCBuf, 4*256);
  586.             FreeArgs(rda);
  587.           }
  588.           else
  589.             PrintFault(IoErr(), "CheckX");
  590.           FreeDosObject(DOS_RDARGS, rda);
  591.         }
  592.     CloseLibrary((struct Library *) xadmasterbase);
  593.       }
  594.       else
  595.         Printf("CheckX requires xadmaster.library version 10 or better.\n");
  596.       CloseLibrary((struct Library *) xfdmasterbase);
  597.     }
  598.     else
  599.       Printf("CheckX requires xfdmaster.library version 39 or better.\n");
  600.     CloseLibrary((struct Library *) dosbase);
  601.   }
  602.  
  603.   return error;
  604. }
  605.  
  606. static void clear(STRPTR buf, ULONG size)
  607. {
  608.   while(size--)
  609.     *(buf++) = 0;
  610. }
  611.  
  612. static void SetLogComment(struct FileData *fd, STRPTR name)
  613. {
  614.   UBYTE com[30];
  615.   struct MsgPort *TimerMP;
  616.  
  617.   if((TimerMP = CreateMsgPort()))
  618.   {
  619.     struct timerequest *TimerIO;
  620.  
  621.     if((TimerIO = (struct timerequest *) CreateIORequest(TimerMP,
  622.     sizeof(struct timerequest))))
  623.     {
  624.       if(!OpenDevice("timer.device",UNIT_VBLANK,
  625.       (struct IORequest *)TimerIO,0))
  626.       {
  627.         struct UtilityBase *utilitybase;
  628.  
  629.         TimerIO->tr_node.io_Command = TR_GETSYSTIME;
  630.         DoIO((struct IORequest *) TimerIO);
  631.         if((utilitybase = (struct UtilityBase *) OpenLibrary("utility.library",37)))
  632.         {
  633.           struct ClockData dat;
  634.  
  635.       ASSIGN_UTIL
  636.           Amiga2Date(TimerIO->tr_time.tv_secs, &dat);
  637.           SPrintF(fd, com, "CheckX " VERSION "." REVISION " - %02ld.%02ld.%ld", dat.mday, dat.month, dat.year);
  638.       CloseLibrary((struct Library *) utilitybase);
  639.       SetComment(name, com);
  640.         }
  641.         CloseDevice((struct IORequest *) TimerIO);
  642.       }
  643.       DeleteIORequest(TimerIO);
  644.     }
  645.     DeleteMsgPort(TimerMP);
  646.   }
  647. }
  648.  
  649. /* This scans a directory and calls DoFileOpen for every file. It
  650.    automatically creates SAVE destination directories when necessary. */
  651. static LONG DoDirectoryScan(struct FileData *fd, STRPTR name, STRPTR sav)
  652. {
  653.   struct AnchorPath *APath;
  654.   LONG error = CHKXERR_SCANERR;
  655.   ULONG retval;
  656.  
  657.   if(!(fd->fd_Flags & CHECKXFLAG_SAVE) || !sav ||
  658.   (fd->fd_SaveDirL = Lock(sav, SHARED_LOCK)))
  659.   {
  660.     if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
  661.     512, MEMF_PUBLIC|MEMF_CLEAR)))
  662.     {
  663.       fd->fd_Name = APath->ap_Buf;
  664.       APath->ap_Strlen = 256;
  665.       for(retval = MatchFirst(name, APath); !retval;
  666.       retval = MatchNext(APath))
  667.       {
  668.         if(APath->ap_Flags & APF_DIDDIR)
  669.         {
  670.           OpenParentDir(fd);
  671.           APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
  672.         }
  673.         else if(APath->ap_Info.fib_DirEntryType > 0)
  674.         {
  675.           if(fd->fd_Flags & CHECKXFLAG_ALL)
  676.           {
  677.             OpenNewDir(fd, APath->ap_Info.fib_FileName);
  678.             APath->ap_Flags |= APF_DODIR;
  679.           }
  680.         }
  681.         else
  682.         {
  683.       fd->fd_Flags &= CHKXCALLFLAGS;
  684.           fd->fd_LinkNum = 0;
  685.           PrintCHKXErr(fd, DoFileOpen(fd));
  686.  
  687.           while(fd->fd_MemList)
  688.             FreeCrunchMemList(fd, fd->fd_MemList->cml_MemoryRegion);
  689.         }
  690.         if((fd->fd_Flags & CHECKXFLAG_SAVE) && !fd->fd_SaveDirL)
  691.         {
  692.           error = CHKXERR_OPENDIR; break;
  693.         }
  694.         if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  695.         {
  696.           error = CHKXERR_BREAK; break;
  697.         }
  698.       }
  699.       MatchEnd(APath);
  700.  
  701.       if(retval == ERROR_NO_MORE_ENTRIES)
  702.         error = 0;
  703.  
  704.       FreeMem(APath, sizeof(struct AnchorPath) + 512);
  705.     }
  706.     else
  707.       error = CHKXERR_NOMEMORY;
  708.  
  709.     if(sav && fd->fd_SaveDirL)
  710.       UnLock(fd->fd_SaveDirL);
  711.   }
  712.   else
  713.     error = CHKXERR_OPENDIR;
  714.  
  715.   return error;
  716. }
  717.  
  718. /* Open a file and call DoGetVirus to scan */
  719. static LONG DoFileOpen(struct FileData *fd)
  720. {
  721.   struct FileInfoBlock *fib;
  722.   LONG ret = 0;
  723.  
  724.   if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  725.   {
  726.     ULONG fh;
  727.  
  728.     if((fh = Open(fd->fd_Name, MODE_OLDFILE)))
  729.     {
  730.       if(ExamineFH(fh, fib))
  731.       {
  732.         APTR mem;
  733.  
  734.     if(!fib->fib_Size)
  735.           ret = CHKXWARN_EMPTY;
  736.         else if((mem = AllocMem(fib->fib_Size, MEMF_ANY)))
  737.         {
  738.           if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
  739.             ret = CHKXERR_READ;
  740.  
  741.           if(!ret && !(ret = AddCrunchMemList(fd, mem, fib->fib_Size)))
  742.             ret = DoGetVirus(fd, mem, fib->fib_Size);
  743.           else
  744.             FreeMem(mem, fib->fib_Size);
  745.         }
  746.         else
  747.         {
  748.           fd->fd_ArcFileFH = fh;
  749.           PrintCHKXErr(fd, CHKXERR_NOMEMORYARC);
  750.       ret = DoFileUnArchive(fd, 0, fib->fib_Size);
  751.         }
  752.       }
  753.       else
  754.         ret = CHKXERR_EXAMINEERR;
  755.       Close(fh);
  756.     }
  757.     else
  758.       ret = CHKXERR_OPENERR;
  759.   
  760.     FreeDosObject(DOS_FIB, fib);
  761.   }
  762.   else
  763.     ret = CHKXERR_NOMEMORY;
  764.  
  765.   return ret;
  766. }
  767.  
  768. /* for SAVE option: open parent directory and try to delete the directory
  769.    we leave. This only succeeds, when the directory is empty. */
  770. static ULONG OpenParentDir(struct FileData *fd)
  771. {
  772.   ULONG g;
  773.   UBYTE name[300];
  774.  
  775.   if((g = fd->fd_SaveDirL))
  776.   {
  777.     NameFromLock(g, name, 300);
  778.     fd->fd_SaveDirL = ParentDir(g);
  779.     UnLock(g);
  780.  
  781.     DeleteFile(name);
  782.   }
  783.   else
  784.     return -1;
  785.  
  786.   return fd->fd_SaveDirL;
  787. }
  788.  
  789. /* Open a new subdirectory for SAVE option */
  790. static ULONG OpenNewDir(struct FileData *fd, STRPTR name)
  791. {
  792.   ULONG g;
  793.  
  794.   if(fd->fd_SaveDirL)
  795.   {
  796.     g = CurrentDir(fd->fd_SaveDirL);
  797.     if(!(fd->fd_SaveDirL = Lock(name, SHARED_LOCK)))
  798.       if((fd->fd_SaveDirL = CreateDir(name)))
  799.         ChangeMode(CHANGE_LOCK, fd->fd_SaveDirL, SHARED_LOCK);
  800.     UnLock(CurrentDir(g));
  801.   }
  802.   else
  803.     return -1;
  804.  
  805.   return fd->fd_SaveDirL;
  806. }
  807.  
  808. static LONG DoGetVirus(struct FileData *fd, APTR buffer, ULONG buflength)
  809. {
  810.   if(fd->fd_Flags & CHECKXFLAG_DEEPNAME)
  811.   {
  812.     if(fd->fd_Flags & CHECKXFLAG_NAMEPRINTED)
  813.     {
  814.       fd->fd_Flags &= ~(CHECKXFLAG_NAMEPRINTED);
  815.       fd->fd_Flags |= CHECKXFLAG_SHORTNAME;
  816.     }
  817.   }
  818.  
  819.   if(fd->fd_Flags & CHECKXFLAG_CRC && buflength)
  820.   {
  821.     register ULONG CRC = ~0, i;
  822.     fd->fd_Flags |= CHECKXFLAG_CRCVALID;
  823.     
  824.     for(i = 0; i < buflength; ++i)
  825.       CRC = fd->fd_CRCBuf[(CRC ^ ((STRPTR)buffer)[i]) & 0xFF] ^ (CRC >> 8);
  826.  
  827.     fd->fd_CRC32 = ~CRC;
  828.   }
  829.  
  830.   if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
  831.   ((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && buflength > 4
  832.   && *((ULONG *)buffer) == HUNK_HEADER))
  833.     PrintCHKXFile(fd);
  834.  
  835.   if(!buflength) /* restarted with empty file */
  836.     return CHKXWARN_EMPTY;
  837.  
  838.   if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
  839.   {
  840.     register APTR mem;
  841.       
  842.     if((mem = AllocMem(buflength, MEMF_ANY)))
  843.     {
  844.       struct xvsFileInfo *fi;
  845.       if((fi = (struct xvsFileInfo *) xvsAllocObject(XVSOBJ_FILEINFO)))
  846.       {
  847.         register ULONG i;
  848.         struct xvsBootInfo *bi;
  849.  
  850.         bi = (struct xvsBootInfo *) xvsAllocObject(XVSOBJ_BOOTINFO);
  851.     /* xvs may modify the buffer! */
  852.         CopyMem(buffer, mem, buflength);
  853.         fi->xvsfi_File = mem;
  854.         fi->xvsfi_FileLen = buflength;
  855.         i = xvsCheckFile(fi);
  856.         if(i == XVSFT_DATAVIRUS)
  857.         {
  858.        PrintCHKXTxt(fd, "Data-Virus '%s'", fi->xvsfi_Name);
  859.        ++fd->fd_NumVirus;
  860.      }
  861.         else if(i == XVSFT_FILEVIRUS)
  862.         {
  863.        PrintCHKXTxt(fd, "File-Virus '%s'", fi->xvsfi_Name);
  864.        ++fd->fd_NumVirus;
  865.      }
  866.         else if(i == XVSFT_LINKVIRUS)
  867.         {
  868.        PrintCHKXTxt(fd, "Link-Virus '%s'", fi->xvsfi_Name);
  869.        ++fd->fd_NumVirus;
  870.      }
  871.      else if(bi)
  872.      {
  873.           bi->xvsbi_Bootblock = mem;
  874.           if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
  875.        {
  876.             PrintCHKXTxt(fd, "Boot-Virus '%s'", bi->xvsbi_Name);
  877.             ++fd->fd_NumVirus;
  878.           }
  879.      }
  880.  
  881.         if(bi)
  882.         {
  883.           STRPTR p, pe;
  884.  
  885.           p = (STRPTR)mem+1;
  886.           pe = (STRPTR)mem+buflength-1024;
  887.           for(;;)
  888.           {
  889.         while(p <= pe && (p[0] != 'D' || p[1] != 'O' || p[2] != 'S' ||
  890.         p[3] > 7))
  891.           ++p;
  892.  
  893.             if(p <= pe)
  894.             {
  895.               bi->xvsbi_Bootblock = p;
  896.           if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
  897.           {
  898.             PrintCHKXTxt(fd, "Boot-Virus '%s' at offset $%lx", bi->xvsbi_Name,
  899.             p-(STRPTR)mem);
  900.             ++fd->fd_NumVirus;
  901.             p += 1024;
  902.           }
  903.           else
  904.             p += 4;
  905.         }
  906.         else
  907.           break;
  908.       }
  909.       xvsFreeObject(bi);
  910.     }
  911.  
  912.         xvsFreeObject(fi);
  913.       }
  914.       else
  915.         PrintCHKXErr(fd, CHKXERR_NOVIRUS);
  916.       FreeMem(mem, buflength);
  917.     }
  918.     else
  919.       PrintCHKXErr(fd, CHKXERR_NOVIRUS);
  920.  
  921.     if(!(fd->fd_Flags & CHECKXFLAG_NOSECTOR))
  922.       PrintCHKXErr(fd, DoSectorCheck(fd, buffer, buflength, 0));
  923.   }
  924.  
  925.   return DoFileUnArchive(fd, buffer, buflength);
  926. }
  927.  
  928. static LONG DoSectorCheck(struct FileData *fd, APTR buffer, ULONG buflength, ULONG pos)
  929. {
  930.   LONG err = 0;
  931.  
  932.   if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
  933.   {
  934.     struct xvsSectorInfo *si;
  935.  
  936.     if((si = (struct xvsSectorInfo *) xvsAllocObject(XVSOBJ_SECTORINFO)))
  937.     {
  938.       ULONG i, j, k;
  939.  
  940.       j = buflength >> 9; /* divide by 512 */
  941.       for(i = 0; i < j; ++i)
  942.       {
  943.         si->xvssi_Sector = ((STRPTR) buffer) + (i<<9);
  944.         si->xvssi_Key = pos + i;
  945.         k = xvsCheckSector(si);
  946.         if(k == XVSST_DESTROYED)
  947.         {
  948.           ++fd->fd_NumSectors;
  949.           PrintCHKXTxt(fd, "Sector %ld destroyed by '%s'", si->xvssi_Key, si->xvssi_Name);
  950.         }
  951.         else if(k == XVSST_INFECTED)
  952.         {
  953.           ++fd->fd_NumSectors;
  954.           PrintCHKXTxt(fd, "Sector %ld infected by '%s'", si->xvssi_Key, si->xvssi_Name);
  955.         }
  956.       }
  957.       xvsFreeObject(si);
  958.     }
  959.     else
  960.       err = CHKXERR_NOSECTOR;
  961.   }
  962.  
  963.   return err;
  964. }
  965.  
  966. /* For bootblocks */
  967. static ASM(LONG) OutHookCheckX(REG(a0, struct Hook *hook), REG(a1, struct xadHookParam *hp))
  968. {
  969.   LONG i, j;
  970.   STRPTR s;
  971.   struct FileData *fd;
  972.  
  973.   fd = (struct FileData *) hook->h_Data;
  974.   switch(hp->xhp_Command)
  975.   {
  976.   case XADHC_WRITE:
  977.     j = hp->xhp_BufferSize;
  978.     s = (STRPTR) hp->xhp_BufferPtr;
  979.     if((i = 1024-hp->xhp_DataPos) > j)
  980.       i = j;
  981.     if(i > 0)
  982.     {
  983.       CopyMem(s, fd->fd_Memory+hp->xhp_DataPos, i);
  984.       hp->xhp_DataPos += i;
  985.       j -= i;
  986.       s += i;
  987.     }
  988.     if(hp->xhp_DataPos == 1024 && i > 0)
  989.     {
  990.       fd->fd_Flags |= CHECKXFLAG_BBEXTRACTED;
  991.       if(((fd->fd_Flags & CHECKXFLAG_XVSLIB) && !(fd->fd_Flags & CHECKXFLAG_NOSECTOR)))
  992.       {
  993.         i = DoSectorCheck(fd, fd->fd_Memory, 1024, 0);
  994.         if(i)
  995.         {
  996.           PrintCHKXErr(fd, i);
  997.           return 10000;
  998.         }
  999.       }
  1000.       else
  1001.         return 10000;
  1002.     }
  1003.     if(hp->xhp_DataPos >= 1024)
  1004.     {
  1005.       LONG k;
  1006.       while(j)
  1007.       {
  1008.         k = hp->xhp_DataPos & 0x1FF;
  1009.         if((i = 512-k) > j)
  1010.           i = j;
  1011.         CopyMem(s, fd->fd_Memory+1024+k, i);
  1012.         hp->xhp_DataPos += i;
  1013.         j -= i;
  1014.         s += i;
  1015.         if(!(hp->xhp_DataPos & 0x1FF))
  1016.         {
  1017.           i = DoSectorCheck(fd, fd->fd_Memory+1024, 512, (hp->xhp_DataPos>>9)-1);
  1018.           if(i)
  1019.           {
  1020.             PrintCHKXErr(fd, i);
  1021.             return 10000;
  1022.           }
  1023.         }
  1024.       }
  1025.     }
  1026.   case XADHC_INIT:
  1027.   case XADHC_FREE:
  1028.   case XADHC_ABORT:
  1029.     break;
  1030.   default: return XADERR_NOTSUPPORTED;
  1031.   }
  1032.  
  1033.   return 0;
  1034. }
  1035.  
  1036. /* To get real file size */
  1037. static ASM(LONG) OutHookCheckXSize(REG(a0, struct Hook *hook), REG(a1, struct xadHookParam *hp))
  1038. {
  1039.   switch(hp->xhp_Command)
  1040.   {
  1041.   case XADHC_WRITE:
  1042.     hp->xhp_DataPos += hp->xhp_BufferSize;
  1043.     hook->h_Data = (APTR) hp->xhp_DataPos;
  1044.   case XADHC_INIT:
  1045.   case XADHC_FREE:
  1046.   case XADHC_ABORT:
  1047.     break;
  1048.   default: return XADERR_NOTSUPPORTED;
  1049.   }
  1050.  
  1051.   return 0;
  1052. }
  1053.  
  1054. static void CheckArcFiles(struct FileData *fd, struct xadArchiveInfo *ai, ULONG disk)
  1055. {
  1056.   struct xadFileInfo *fi;
  1057.   struct TagItem ti[6];
  1058.   LONG numloop = 0;
  1059.   LONG trypwd = 0;
  1060.  
  1061.   ti[0].ti_Tag = XAD_OUTMEMORY;
  1062.   ti[1].ti_Tag = XAD_OUTSIZE;
  1063.   ti[2].ti_Tag = XAD_ENTRYNUMBER;
  1064.   ti[3].ti_Tag = XAD_PROGRESSHOOK;
  1065.   ti[3].ti_Data = (ULONG) &breakhook;
  1066.   ti[4].ti_Tag = TAG_DONE;
  1067.  
  1068.   fi = ai->xai_FileInfo;
  1069.   while(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C) && fi)
  1070.   {
  1071.     APTR dest;
  1072.  
  1073.     if(!(fi->xfi_Flags & (XADFIF_DIRECTORY|XADFIF_LINK)))
  1074.     {
  1075.       LONG err = 0;
  1076.       ULONG flags, size, linknum;
  1077.  
  1078.       flags = fd->fd_Flags;
  1079.       linknum = fd->fd_LinkNum;
  1080.       fd->fd_LinkNum = 0;
  1081.       if(!(fi->xfi_Flags & XADFIF_NOFILENAME))
  1082.         fd->fd_Flags &= ~(CHKXNAMEFLAGS);
  1083.       fd->fd_Name = fi->xfi_FileName;
  1084.       fd->fd_RecurseDepth++;
  1085.  
  1086.       size = fi->xfi_Size;
  1087.       if(fi->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
  1088.       {
  1089.     struct Hook hook = {{0,0},(ULONG (*)()) OutHookCheckXSize, 0, 0};
  1090.       struct TagItem ti[5];
  1091.  
  1092.     ti[0].ti_Tag = XAD_OUTHOOK;
  1093.     ti[0].ti_Data = (ULONG) &hook;
  1094.       ti[1].ti_Tag = XAD_ENTRYNUMBER;
  1095.     ti[1].ti_Data = fi->xfi_EntryNumber;
  1096.         ti[2].ti_Tag = XAD_PROGRESSHOOK;
  1097.         ti[2].ti_Data = (ULONG) &breakhook;
  1098.       ti[3].ti_Tag = trypwd ? XAD_PASSWORD : TAG_IGNORE;
  1099.       ti[3].ti_Data = (ULONG) fd->fd_Password;
  1100.         ti[4].ti_Tag = TAG_DONE;
  1101.  
  1102.         if(!(err = (disk ? xadDiskFileUnArcA(ai, ti) : xadFileUnArcA(ai, ti))))
  1103.       size = (ULONG) hook.h_Data;
  1104.       }
  1105.  
  1106.       if(!size)
  1107.       {
  1108.         if(!err)
  1109.           err = CHKXWARN_EMPTY;
  1110.       }
  1111.       else if((dest = AllocMem(size, MEMF_PUBLIC)))
  1112.       {
  1113.         if(!(err = AddCrunchMemList(fd, dest, size)))
  1114.         {
  1115.       ti[0].ti_Data = (ULONG) dest;
  1116.       ti[1].ti_Data = size;
  1117.       ti[2].ti_Data = fi->xfi_EntryNumber;
  1118.           ti[4].ti_Tag = trypwd ? XAD_PASSWORD : TAG_IGNORE;
  1119.       ti[4].ti_Data = (ULONG) fd->fd_Password;
  1120.  
  1121.           if((err = disk ? xadDiskFileUnArcA(ai, ti) : xadFileUnArcA(ai, ti)))
  1122.       {
  1123.         if(disk)
  1124.           err = CHKXERR_READ;
  1125.         else
  1126.               err += XADERR_OFFSET;
  1127.           }
  1128.           else
  1129.             err = DoGetVirus(fd, dest, size);
  1130.           FreeCrunchMemList(fd, dest);
  1131.         }
  1132.         else
  1133.           FreeMem(dest, size);
  1134.       }
  1135.       else
  1136.         err = CHKXERR_NOMEMORY;
  1137.  
  1138.       if((err == XADERR_OFFSET + XADERR_PASSWORD) && !numloop)
  1139.       {
  1140.         if(!trypwd && fd->fd_Password[0])
  1141.         {
  1142.           ++trypwd; err = 0; numloop = -2;
  1143.         }
  1144.         else
  1145.         {
  1146.           struct Library *xpkbase;
  1147.           if((fd->fd_Flags & CHECKXFLAG_ASKPWD) && (xpkbase = OpenLibrary(XPKNAME, 4)))
  1148.           {
  1149.             if(!XpkPassRequestTags(XPK_PasswordBuf, fd->fd_Password, XPK_PassBufSize,
  1150.             PASSWORDSIZE, XPK_PassTitle, fd->fd_Name, TAG_DONE))
  1151.             {
  1152.               numloop = -1; err = 0;
  1153.               ++trypwd;
  1154.             }
  1155.             CloseLibrary(xpkbase);
  1156.           }
  1157.         }
  1158.       }
  1159.  
  1160.       if(err)
  1161.       {
  1162.         if(fi->xfi_Flags & XADFIF_NOFILENAME)
  1163.           fd->fd_Flags &= ~(CHKXNAMEFLAGS);
  1164.         PrintCHKXErr(fd, err);
  1165.       }
  1166.  
  1167.       --fd->fd_RecurseDepth;
  1168.       fd->fd_Flags = flags;
  1169.       fd->fd_LinkNum = linknum;
  1170.     }
  1171.     if(++numloop)
  1172.     {
  1173.       fi = fi->xfi_Next;
  1174.       numloop = 0;
  1175.     }
  1176.     else
  1177.       ++numloop;
  1178.   }
  1179. }
  1180.  
  1181. /* Tests if a file is an archive. When yes, the archive is unarchived and
  1182.    the result files are scanned. Else DoFileUnLink is called.
  1183. */
  1184. static LONG DoFileUnArchive(struct FileData *fd, APTR buffer, ULONG buflength)
  1185. {
  1186.   LONG err = 0;
  1187.   struct TagItem tih[2];
  1188.   struct xadArchiveInfo *ai;
  1189.  
  1190.   if(buflength == 42374 && !(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE))
  1191.   {
  1192.     if(!(fd->fd_Flags & CHECKXFLAG_CRCVALID) && fd->fd_CRCBuf)
  1193.     {
  1194.       register ULONG CRC = ~0, i;
  1195.       fd->fd_Flags |= CHECKXFLAG_CRCVALID;
  1196.     
  1197.       for(i = 0; i < buflength; ++i)
  1198.         CRC = fd->fd_CRCBuf[(CRC ^ ((STRPTR)buffer)[i]) & 0xFF] ^ (CRC >> 8);
  1199.  
  1200.       fd->fd_CRC32 = ~CRC;
  1201.     }
  1202.     if(fd->fd_CRC32 == 0x9A0D79CC) /* strange unscanable file (in useful times :-) */
  1203.     {
  1204.       PrintCHKXErr(fd, CHKXERR_EXAMINEERR);
  1205.       err = DoFileUnLink(fd, buffer, buflength);
  1206.     }
  1207.   }
  1208.  
  1209.   if(buffer) { tih[0].ti_Tag = XAD_INMEMORY; tih[0].ti_Data = (ULONG) buffer; }
  1210.   else { tih[0].ti_Tag = XAD_INFILEHANDLE; tih[0].ti_Data = (ULONG) fd->fd_ArcFileFH; }
  1211.   tih[1].ti_Tag = TAG_DONE;
  1212.  
  1213.   if((ai = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  1214.   {
  1215.     STRPTR arcname;
  1216.  
  1217.     arcname = fd->fd_Name;
  1218.     if(!xadGetInfo(ai, XAD_INSIZE, buflength, XAD_PROGRESSHOOK, &breakhook, TAG_MORE, tih))
  1219.     {
  1220.       if(ai->xai_Flags & XADAIF_FILECORRUPT)
  1221.       {
  1222.         ++fd->fd_CorruptedArchives;
  1223.         PrintCHKXTxt(fd, "%s (ARCHIVE, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
  1224.       }
  1225.       else
  1226.         PrintCHKXTxt(fd, "%s (ARCHIVE)", ai->xai_Client->xc_ArchiverName);
  1227.         
  1228.       if(!(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo ||
  1229.       !(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo))
  1230.       {
  1231.         if(buffer)
  1232.           err = DoFileUnLink(fd, buffer, buflength);
  1233.       }
  1234.       else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
  1235.         err = CHKXERR_OPENERR;
  1236.       else
  1237.       {
  1238.     if(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo)
  1239.       CheckArcFiles(fd, ai, 0);
  1240.     if(!(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo)
  1241.     {
  1242.       STRPTR buf;
  1243.  
  1244.       /* reduce stacksize, as we have a recursive program */
  1245.       if((buf = (STRPTR) AllocMem(1024+512, MEMF_PUBLIC)))
  1246.       {
  1247.             LONG numloop = 0; LONG trypwd = 0;
  1248.             ULONG flags;
  1249.             STRPTR name;
  1250.         struct xadDiskInfo *di;
  1251.         struct xadArchiveInfo *aid;
  1252.         di = ai->xai_DiskInfo;
  1253.  
  1254.             flags = fd->fd_Flags;
  1255.             name = fd->fd_Name;
  1256.         while(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C) && di)
  1257.         {
  1258.           if((di->xdi_Flags & XADDIF_CRYPTED) && fd->fd_Password[0])
  1259.             trypwd = 1;
  1260.           if(di->xdi_SectorSize != 512 || (di->xdi_TrackSectors != 11 &&
  1261.           di->xdi_TrackSectors != 22) || (!(di->xdi_Flags & XADDIF_NOHEADS) &&
  1262.           di->xdi_Heads != 2) || (!(di->xdi_Flags & XADDIF_NOCYLINDERS) &&
  1263.           di->xdi_Cylinders != 80))
  1264.             SPrintF(fd, buf, "-disk image %ld", di->xdi_EntryNumber);
  1265.           else
  1266.           {
  1267.             if(!(di->xdi_Flags & (XADDIF_NOHIGHCYL|XADDIF_NOLOWCYL)) &&
  1268.          (di->xdi_LowCyl || di->xdi_HighCyl != 79))
  1269.                   SPrintF(fd, buf, "-disk image %ld (%s, %ld to %ld)",
  1270.                   di->xdi_EntryNumber, di->xdi_TrackSectors == 22 ?
  1271.                   "HD" : "DD", di->xdi_LowCyl, di->xdi_HighCyl);
  1272.                 else
  1273.                   SPrintF(fd, buf, "-disk image %ld (%s)",
  1274.                   di->xdi_EntryNumber, di->xdi_TrackSectors == 22 ? "HD" : "DD");
  1275.               }
  1276.       
  1277.               fd->fd_Flags &= ~(CHKXNAMEFLAGS);
  1278.           fd->fd_Name = buf;
  1279.               PrintCHKXFile(fd);
  1280.  
  1281.           if(di->xdi_TextInfo)
  1282.           {
  1283.                 struct xadTextInfo *ti;
  1284.                 ULONG flags, i = 1, linknum;
  1285.  
  1286.             for(ti = di->xdi_TextInfo; ti; ti = ti->xti_Next)
  1287.             {
  1288.               if(ti->xti_Size && ti->xti_Text)
  1289.               {
  1290.                     flags = fd->fd_Flags;
  1291.                     fd->fd_Flags &= ~(CHKXNAMEFLAGS);
  1292.                     fd->fd_Flags |= CHECKXFLAG_NOFREEMEM;
  1293.                     fd->fd_RecurseDepth++;
  1294.                     linknum = fd->fd_LinkNum;
  1295.                     fd->fd_LinkNum = 0;
  1296.                     SPrintF(fd, buf, "--infotext %ld (size %ld)", i, ti->xti_Size);
  1297.                     PrintCHKXErr(fd, DoGetVirus(fd, ti->xti_Text, ti->xti_Size));
  1298.                     --fd->fd_RecurseDepth;
  1299.                     fd->fd_Flags = flags;
  1300.                     fd->fd_LinkNum = linknum;
  1301.                   }
  1302.                   ++i;
  1303.                 }
  1304.               }
  1305.  
  1306.           /* check bootblock here - special outhook for bootblock extraction */
  1307.           if(!di->xdi_LowCyl) /* boot check only, when first block! */
  1308.           {
  1309.             struct Hook hook = {{0,0},(ULONG (*)()) OutHookCheckX, 0};
  1310.  
  1311.         fd->fd_Memory = buf;
  1312.             hook.h_Data = fd;
  1313.             xadDiskUnArc(ai, XAD_ENTRYNUMBER, di->xdi_EntryNumber,
  1314.             XAD_OUTHOOK, &hook, XAD_PROGRESSHOOK, &breakhook,
  1315.             trypwd ? XAD_PASSWORD : TAG_IGNORE, fd->fd_Password,
  1316.             TAG_DONE);
  1317.             if(fd->fd_Flags & CHECKXFLAG_BBEXTRACTED) /* special hook return code! */
  1318.             {
  1319.               struct xvsBootInfo *bi;
  1320.  
  1321.           fd->fd_Flags &= ~CHECKXFLAG_BBEXTRACTED; /* clear flag */
  1322.               if((bi = (struct xvsBootInfo *) xvsAllocObject(XVSOBJ_BOOTINFO)))
  1323.                 {
  1324.                 bi->xvsbi_Bootblock = buf;
  1325.                 if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
  1326.                 {
  1327.                   PrintCHKXTxt(fd, "Boot-Virus '%s'", bi->xvsbi_Name);
  1328.                   ++fd->fd_NumVirus;
  1329.                 }
  1330.                 xvsFreeObject(bi);
  1331.                 }
  1332.                 else
  1333.                   PrintCHKXErr(fd, CHKXERR_NOBOOTVIRUS);
  1334.               }
  1335.               else
  1336.                 PrintCHKXErr(fd, CHKXERR_NOBOOTVIRUS);
  1337.           }
  1338.     
  1339.           if((aid = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  1340.           {
  1341.             struct TagItem ti[5];
  1342.             struct xadClient *cl;
  1343.  
  1344.           ti[0].ti_Tag = XAD_INSIZE;
  1345.           ti[0].ti_Data = buflength;
  1346.           ti[1].ti_Tag = XAD_ENTRYNUMBER;
  1347.           ti[1].ti_Data = di->xdi_EntryNumber;
  1348.                 ti[2].ti_Tag = XAD_PROGRESSHOOK;
  1349.                 ti[2].ti_Data = (ULONG) &breakhook;
  1350.             ti[3].ti_Tag = trypwd ? XAD_PASSWORD : TAG_IGNORE;
  1351.             ti[3].ti_Data = (ULONG) fd->fd_Password;
  1352.           ti[4].ti_Tag = TAG_MORE;
  1353.           ti[4].ti_Data = (ULONG) tih;
  1354.     
  1355.           if(!(err = xadGetDiskInfo(aid, XAD_NOEMPTYERROR, 1, XAD_PROGRESSHOOK, &breakhook,
  1356.           XAD_INDISKARCHIVE, ti, TAG_DONE)))
  1357.           {
  1358.             if(aid->xai_Flags & XADAIF_FILECORRUPT)
  1359.             {
  1360.                     ++fd->fd_CorruptedArchives;
  1361.                     PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", aid->xai_Client->xc_ArchiverName);
  1362.             }
  1363.                   else
  1364.                     PrintCHKXTxt(fd, "%s (FILESYSTEM)", aid->xai_Client->xc_ArchiverName);
  1365.           CheckArcFiles(fd, aid, 1);
  1366.           cl = aid->xai_Client->xc_Next;
  1367.           xadFreeInfo(aid);
  1368.           while(cl) /* multiple filesystems */
  1369.           {
  1370.               if(!xadGetDiskInfo(aid, XAD_NOEMPTYERROR, 1, XAD_INDISKARCHIVE, ti,
  1371.               XAD_PROGRESSHOOK, &breakhook, XAD_STARTCLIENT, cl, TAG_DONE))
  1372.               {
  1373.                 if(aid->xai_Flags & XADAIF_FILECORRUPT)
  1374.                 {
  1375.                         ++fd->fd_CorruptedArchives;
  1376.                         PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", aid->xai_Client->xc_ArchiverName);
  1377.                 }
  1378.                       else
  1379.                         PrintCHKXTxt(fd, "%s (FILESYSTEM)", aid->xai_Client->xc_ArchiverName);
  1380.               CheckArcFiles(fd, aid, 1);
  1381.               cl = aid->xai_Client->xc_Next;
  1382.               xadFreeInfo(aid);
  1383.             }
  1384.             else
  1385.               cl = 0;
  1386.           }
  1387.           }
  1388.           else
  1389.           {
  1390.                   if((err == XADERR_PASSWORD) && !numloop)
  1391.                   {
  1392.                     if(!trypwd && fd->fd_Password[0])
  1393.                     {
  1394.                       ++trypwd; err = 0; numloop = -2;
  1395.                     }
  1396.                     else
  1397.                     {
  1398.                       struct Library *xpkbase;
  1399.                       if((fd->fd_Flags & CHECKXFLAG_ASKPWD) && (xpkbase = OpenLibrary(XPKNAME, 4)))
  1400.                       {
  1401.                         if(!XpkPassRequestTags(XPK_PasswordBuf, fd->fd_Password, XPK_PassBufSize,
  1402.                         PASSWORDSIZE, XPK_PassTitle, name, TAG_DONE))
  1403.                         {
  1404.                           numloop = -1; err = 0;
  1405.                           ++trypwd;
  1406.                         }
  1407.                         CloseLibrary(xpkbase);
  1408.                       }
  1409.                     }
  1410.                   }
  1411.             if(err != XADERR_FILESYSTEM && err)
  1412.               PrintCHKXErr(fd, XADERR_OFFSET + err);
  1413.             err = 0;
  1414.           }
  1415.           xadFreeObjectA(aid, 0);
  1416.           }
  1417.  
  1418.               if(++numloop)
  1419.               {
  1420.                 di = di->xdi_Next;
  1421.                 numloop = 0;
  1422.               }
  1423.               else
  1424.                 ++numloop;
  1425.             } /* while */
  1426.             fd->fd_Flags = flags;
  1427.             FreeMem(buf, 1024+512);
  1428.           } /* AllocMem buffer */
  1429.           else
  1430.             err = CHKXERR_NOMEMORY;
  1431.         } /* is there a disk entry? */
  1432.         if(!OpenParentDir(fd))
  1433.           err = CHKXERR_OPENDIR;
  1434.       }
  1435.  
  1436.       xadFreeInfo(ai);
  1437.     } /* xadGetInfo */
  1438.     else if(!xadGetDiskInfo(ai, XAD_NOEMPTYERROR, 1, XAD_PROGRESSHOOK, &breakhook,
  1439.     XAD_INSIZE, buflength, TAG_MORE, tih))
  1440.     {
  1441.       struct xadClient *cl;
  1442.       ULONG isvalid = 1;
  1443.  
  1444.       if(ai->xai_Flags & XADAIF_FILECORRUPT)
  1445.       {
  1446.         ++fd->fd_CorruptedArchives;
  1447.         PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
  1448.       }
  1449.       else
  1450.         PrintCHKXTxt(fd, "%s (FILESYSTEM)", ai->xai_Client->xc_ArchiverName);
  1451.  
  1452.       if(fd->fd_Flags & CHECKXFLAG_NOUNTRACK)
  1453.       {
  1454.         if(buffer)
  1455.           err = DoFileUnLink(fd, buffer, buflength);
  1456.       }
  1457.       else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
  1458.         err = CHKXERR_OPENERR;
  1459.       else
  1460.       {
  1461.         CheckArcFiles(fd, ai, 1);
  1462.         while(isvalid && (cl = ai->xai_Client->xc_Next))
  1463.         {
  1464.           xadFreeInfo(ai);
  1465.           if(!xadGetDiskInfo(ai, XAD_NOEMPTYERROR, 1, XAD_PROGRESSHOOK, &breakhook,
  1466.           XAD_INSIZE, buflength, XAD_STARTCLIENT, cl, TAG_MORE, tih))
  1467.           {
  1468.             if(ai->xai_Flags & XADAIF_FILECORRUPT)
  1469.             {
  1470.               ++fd->fd_CorruptedArchives;
  1471.               PrintCHKXTxt(fd, "%s (FILESYSTEM, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
  1472.             }
  1473.             else
  1474.               PrintCHKXTxt(fd, "%s (FILESYSTEM)", ai->xai_Client->xc_ArchiverName);
  1475.             CheckArcFiles(fd, ai, 1);
  1476.           }
  1477.           else
  1478.             isvalid = 0;
  1479.         } 
  1480.         if(!OpenParentDir(fd))
  1481.           err = CHKXERR_OPENDIR;
  1482.       }
  1483.       if(isvalid)
  1484.         xadFreeInfo(ai);
  1485.     }
  1486.     else if(buffer)
  1487.       err = DoFileUnLink(fd, buffer, buflength);
  1488.  
  1489.     fd->fd_Name = arcname;
  1490.     xadFreeObjectA(ai, 0);
  1491.   }
  1492.   else
  1493.     err = CHKXERR_NOMEMORY;
  1494.  
  1495.   return err;
  1496. }
  1497.  
  1498. /* Tries to unlink a file. When the file was linked, we call DoGetVirus
  1499.    for the two parts to check if they may be archives, else we call
  1500.    DoFileUnCrunch.
  1501. */
  1502. static LONG DoFileUnLink(struct FileData *fd, APTR buffer, ULONG buflength)
  1503. {
  1504.   LONG ret = CHKXERR_NOMEMORY;
  1505.   struct xfdLinkerInfo *xli;
  1506.  
  1507.   if((xli = (struct xfdLinkerInfo *) xfdAllocObject(XFDOBJ_LINKERINFO)))
  1508.   {
  1509.     xli->xfdli_Buffer = buffer;
  1510.     xli->xfdli_BufLen = buflength;
  1511.     if(xfdRecogLinker(xli))
  1512.     {
  1513.       PrintCHKXTxt(fd, xli->xfdli_LinkerName);
  1514.       if(fd->fd_Flags & CHECKXFLAG_NOUNLINK)
  1515.         ret = DoFileUnCrunch(fd, buffer, buflength);
  1516.       else if(xfdUnlink(xli))
  1517.       {
  1518.         ULONG flags;
  1519.     fd->fd_Flags |= CHECKXFLAG_LINKED;
  1520.         ++fd->fd_RecurseDepth;
  1521.         ++fd->fd_LinkNum;
  1522.     flags = fd->fd_Flags;
  1523.     fd->fd_Flags |= CHECKXFLAG_NOFREEMEM;
  1524.         PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save1,
  1525.         xli->xfdli_SaveLen1));
  1526.         ++fd->fd_LinkNum;
  1527.         fd->fd_Flags = flags; /* CHECKXFLAG_NOFREEMEM is cleared */
  1528.         PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save2,
  1529.         xli->xfdli_SaveLen2));
  1530.         ret = 0;
  1531.         --fd->fd_RecurseDepth;
  1532.       }
  1533.       else
  1534.         ret = XFDERR_OFFSET + xli->xfdli_Error;
  1535.     }
  1536.     else
  1537.       ret = DoFileUnCrunch(fd, buffer, buflength);
  1538.  
  1539.     xfdFreeObject(xli);
  1540.   }
  1541.   return ret;
  1542. }
  1543.  
  1544. /* Tries to decrunch a file. When it is crunched, we decrunch it and call
  1545.    DoGetVirus to start the loop again. Else we call unstripping.
  1546. */
  1547. static LONG DoFileUnCrunch(struct FileData *fd, APTR buffer, ULONG buflength)
  1548. {
  1549.   LONG ret = CHKXERR_NOMEMORY;
  1550.   struct xfdBufferInfo *xbi;
  1551.  
  1552.   if((xbi = (struct xfdBufferInfo *) xfdAllocObject(XFDOBJ_BUFFERINFO)))
  1553.   {
  1554.     xbi->xfdbi_SourceBuffer = buffer;
  1555.     xbi->xfdbi_SourceBufLen = buflength;
  1556.     xbi->xfdbi_Flags = XFDFF_RECOGEXTERN;
  1557.     if(xfdRecogBuffer(xbi))
  1558.     {
  1559.       struct Library *xpkbase;
  1560.       STRPTR buf = 0;
  1561.       ULONG buflen = 0;
  1562.  
  1563.       PrintCHKXTxt(fd, xbi->xfdbi_PackerFlags & XFDPFF_ADDR ? "%s (ADDRESS)" :
  1564.       "%s", xbi->xfdbi_PackerName);
  1565.  
  1566.       if(fd->fd_Flags & CHECKXFLAG_ASKPWD && (xpkbase =
  1567.       OpenLibrary(XPKNAME, 4)))
  1568.       {
  1569.     ASSIGN_XPK
  1570.         if(xbi->xfdbi_PackerFlags & XFDPFF_PASSWORD)
  1571.         {
  1572.           buflen = (xbi->xfdbi_MaxSpecialLen == 0xFFFF) ? 256 :
  1573.         xbi->xfdbi_MaxSpecialLen;
  1574.           if((buf = (STRPTR) AllocMem(buflen, MEMF_ANY|MEMF_CLEAR)))
  1575.       {
  1576.             if(!XpkPassRequestTags(XPK_PasswordBuf, buf, XPK_PassTitle, fd->fd_Name, 
  1577.             XPK_PassBufSize, buflen, TAG_DONE))
  1578.           xbi->xfdbi_Special = buf;
  1579.       }
  1580.         }
  1581.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY16)
  1582.         {
  1583.       if(!XpkPassRequestTags(XPK_Key16BitPtr, &buflen, XPK_PassTitle, fd->fd_Name, TAG_DONE))
  1584.         xbi->xfdbi_Special = &buflen;
  1585.         }
  1586.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY32)
  1587.         {
  1588.       if(!XpkPassRequestTags(XPK_Key32BitPtr, &buflen, XPK_PassTitle, fd->fd_Name, TAG_DONE))
  1589.             xbi->xfdbi_Special = &buflen;
  1590.         }
  1591.     CloseLibrary(xpkbase);
  1592.       }
  1593.       if(fd->fd_Flags & CHECKXFLAG_NODECRUNCH)
  1594.         ret = DoFileStrip(fd, buffer, buflength);
  1595.       else if(xfdDecrunchBuffer(xbi))
  1596.       {
  1597.         if((xbi->xfdbi_PackerFlags & XFDPFF_ADDR) &&
  1598.         !(fd->fd_Flags & CHECKXFLAG_ADDRESS))
  1599.         {
  1600.       fd->fd_Flags |= CHECKXFLAG_ADDRESS;
  1601.           PrintCHKXErr(fd, SaveUncrFile(fd, buffer, buflength));
  1602.         }
  1603.     fd->fd_Flags |= CHECKXFLAG_CRUNCHED;
  1604.         FreeCrunchMemList(fd, buffer);
  1605.         ++fd->fd_RecurseDepth;
  1606.         if(!(ret = AddCrunchMemList(fd, xbi->xfdbi_TargetBuffer,
  1607.         xbi->xfdbi_TargetBufLen)))
  1608.         {
  1609.           PrintCHKXErr(fd, DoGetVirus(fd, xbi->xfdbi_TargetBuffer,
  1610.             xbi->xfdbi_TargetBufSaveLen));
  1611.         }
  1612.         else
  1613.           FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
  1614.         --fd->fd_RecurseDepth;
  1615.       }
  1616.       else
  1617.         ret = XFDERR_OFFSET + xbi->xfdbi_Error;
  1618.  
  1619.       if(buf)
  1620.         FreeMem(buf, buflen);
  1621.     }
  1622.     else
  1623.       ret = DoFileStrip(fd, buffer, buflength);
  1624.  
  1625.     xfdFreeObject(xbi);
  1626.   }
  1627.   return ret;
  1628. }
  1629.  
  1630. /* Tries to strip useless hunks in a file. When there are some, we remove
  1631.    them and call DoGetVirus to start the loop again. Else we finish.
  1632.    When either unlinking or uncrunching happened in past loops, we may
  1633.    save the file when there was SAVE option.
  1634. */
  1635. static LONG DoFileStrip(struct FileData *fd, APTR buffer, ULONG buflength)
  1636. {
  1637.   LONG ret = 0;
  1638.   ULONG reslength = buflength;
  1639.  
  1640.   if(*((ULONG *) buffer) == 0x000003F3 && !(fd->fd_Flags &
  1641.   CHECKXFLAG_NOSTRIP))
  1642.     xfdStripHunks(buffer, buflength, &reslength,
  1643.     XFDSHF_NAME|XFDSHF_SYMBOL|XFDSHF_DEBUG);
  1644.     /* errors are not interpreted */
  1645.  
  1646.   if(buflength > reslength)
  1647.   {
  1648.     fd->fd_Flags |= CHECKXFLAG_STRIPPED;
  1649.     PrintCHKXTxt(fd, "%ld bytes stripped", buflength-reslength);
  1650.     ret = DoGetVirus(fd, buffer, reslength);
  1651.   }
  1652.   else if(!(fd->fd_Flags & CHECKXFLAG_ADDRESS))
  1653.     ret = SaveUncrFile(fd, buffer, buflength);
  1654.  
  1655.   FreeCrunchMemList(fd, buffer);
  1656.  
  1657.   return ret;
  1658. }
  1659.  
  1660. /* Print file name */
  1661. static void PrintCHKXFile(struct FileData *fd)
  1662. {
  1663.   STRPTR name = fd->fd_Name;
  1664.   UBYTE i;
  1665.  
  1666.   if((fd->fd_Flags & CHECKXFLAG_NAMEPRINTED))
  1667.     return;
  1668.   else if(fd->fd_Flags & CHECKXFLAG_SHORTNAME)
  1669.     name = FilePart(name);
  1670.  
  1671.   if(fd->fd_Flags & CHECKXFLAG_DEBUG)
  1672.   {
  1673.     if(fd->fd_Flags & CHECKXFLAG_CRC)
  1674.       KPrintf(fd, (fd->fd_Flags & CHECKXFLAG_CRCVALID) ? "%08lx " :
  1675.       "-------- ", fd->fd_CRC32);
  1676.     for(i = 1; i < fd->fd_RecurseDepth; ++i)
  1677.       KPutC('*', fd);
  1678.     KPrintf(fd, fd->fd_LinkNum ? "%s.%ld\n" : "%s\n", name, fd->fd_LinkNum);
  1679.   }
  1680.  
  1681.   if(fd->fd_LogFileFH)
  1682.   {
  1683.     if(fd->fd_Flags & CHECKXFLAG_CRC)
  1684.       FPrintf(fd->fd_LogFileFH, (fd->fd_Flags & CHECKXFLAG_CRCVALID) ?
  1685.       "%08lx " : "-------- ", fd->fd_CRC32);
  1686.     for(i = 1; i < fd->fd_RecurseDepth; ++i)
  1687.       FPutC(fd->fd_LogFileFH, '*');
  1688.     FPrintf(fd->fd_LogFileFH, fd->fd_LinkNum ? "%s.%ld\n" : "%s\n",
  1689.     name, fd->fd_LinkNum);
  1690.   }
  1691.   if(!(fd->fd_Flags & CHECKXFLAG_QUIET))
  1692.   {
  1693.     if(fd->fd_Flags & CHECKXFLAG_CRC)
  1694.       Printf((fd->fd_Flags & CHECKXFLAG_CRCVALID) ? "%08lx " : "-------- ",
  1695.       fd->fd_CRC32);
  1696.     for(i = 1; i < fd->fd_RecurseDepth; ++i)
  1697.       FPutC(Output(), '*');
  1698.     Printf(fd->fd_LinkNum ? "%s.%ld\n" : "%s\n", name, fd->fd_LinkNum);
  1699.   }
  1700.   fd->fd_Flags |= CHECKXFLAG_NAMEPRINTED;
  1701. }
  1702.  
  1703. static void PrintCHKXErr(struct FileData *fd, LONG err)
  1704. {
  1705.   if(err)
  1706.   {
  1707.     STRPTR txt = 0, txt2;
  1708.  
  1709.     if(err > XFDERR_OFFSET)
  1710.     {
  1711.       ++fd->fd_XFDErrors;
  1712.       txt2 = "XFD-Error %ld: %s";
  1713.       err -= XFDERR_OFFSET;
  1714.       txt = xfdGetErrorText(err);
  1715.     }
  1716.     else if(err > XADERR_OFFSET)
  1717.     {
  1718.       ++fd->fd_XADErrors;
  1719.       txt2 = "XAD-Error %ld: %s";
  1720.       err -= XADERR_OFFSET;
  1721.       txt = xadGetErrorText(err);
  1722.     }
  1723.     else if(err > CHXWARN_OFFSET)
  1724.     {
  1725.       ++fd->fd_CHKXWarnings;
  1726.       txt2 = "CheckX-Warning %ld: %s";
  1727.       switch(err)
  1728.       {
  1729.       case CHKXWARN_NOVIRUS:    txt = "Virus-Checking disabled!";                        break;
  1730.       case CHKXWARN_XVSSELFTEST:txt = "The xvs.library is modified, maybe the system is virus infected!";    break;
  1731.       case CHKXWARN_MEMVIRUS:    txt = "Your system memory was virus infected!";                    break;
  1732.       case CHKXWARN_EMPTY:    txt = "file is empty";                                break;
  1733.       }
  1734.       err -= CHXWARN_OFFSET;
  1735.     }
  1736.     else
  1737.     {
  1738.       ++fd->fd_CHKXErrors;
  1739.       txt2 = "CheckX-Error %ld: %s";
  1740.       switch(err)
  1741.       {
  1742.       case CHKXERR_NOMEMORY:    txt = "not enough memory";            break;
  1743.       case CHKXERR_EXAMINEERR:    txt = "examining failed";            break;
  1744.       case CHKXERR_OPENERR:    txt = "opening file failed";            break;
  1745.       case CHKXERR_READ:    txt = "reading failed";                break;
  1746.       case CHKXERR_SCANERR:    txt = "directory scan failed";            break;
  1747.       case CHKXERR_BREAK:    txt = "user break";                break;
  1748.       case CHKXERR_OPENDIR:    txt = "opening directory failed";        break;
  1749.       case CHKXERR_RESOURCE:    txt = "needed resource not available";        break;
  1750.       case CHKXERR_NOBOOTVIRUS:    txt = "could not check for bootblock virus";    break;
  1751.       case CHKXERR_WRITE:    txt = "writing failed";                break;
  1752.       case CHKXERR_NOVIRUS:    txt = "could not check for virus";        break;
  1753.       case CHKXERR_NOMEMORYARC:    txt = "not enough memory for full tests";    break;
  1754.       case CHKXERR_NOSECTOR:    txt = "could not check sectors";        break;
  1755.       }
  1756.     }
  1757.  
  1758.     PrintCHKXTxt(fd, txt2, err, txt);
  1759.   }
  1760. }
  1761.  
  1762. /* Print type text */
  1763. static void PrintCHKXTxt(struct FileData *fd, STRPTR txt, ...)
  1764. {
  1765.   UBYTE i, j;
  1766.  
  1767.   if(fd->fd_Flags & CHECKXFLAG_MASTERTEXT)
  1768.     j = 0;
  1769.   else
  1770.   {
  1771.     j = fd->fd_RecurseDepth;
  1772.     if(fd->fd_CRC32) j+= 9;
  1773.     PrintCHKXFile(fd);
  1774.   }
  1775.   if(fd->fd_Flags & CHECKXFLAG_DEBUG)
  1776.   {
  1777.     for(i = 0; i < j; ++i)
  1778.       KPutC(' ', fd);
  1779.     RawDoFmt(txt, &txt+1, (void (*)()) KPutC, fd);
  1780.     KPutC('\n', fd);
  1781.   }
  1782.  
  1783.   if(fd->fd_LogFileFH)
  1784.   {
  1785.     for(i = 0; i < j; ++i)
  1786.       FPutC(fd->fd_LogFileFH, ' ');
  1787.     VFPrintf(fd->fd_LogFileFH, txt, &txt+1);
  1788.     FPutC(fd->fd_LogFileFH, '\n');
  1789.     Flush(fd->fd_LogFileFH);
  1790.   }
  1791.  
  1792.   if(!(fd->fd_Flags & CHECKXFLAG_QUIET))
  1793.   {
  1794.     for(i = 0; i < j; ++i)
  1795.       FPutC(Output(), ' ');
  1796.     VPrintf(txt, &txt+1);
  1797.     FPutC(Output(), '\n');
  1798.   }
  1799. }
  1800.  
  1801. /* Add memory to the memory list. */
  1802. static LONG AddCrunchMemList(struct FileData *fd, APTR reg, ULONG size)
  1803. {
  1804.   struct CrunchMemList *ml;
  1805.  
  1806.   if((ml = (struct CrunchMemList *) AllocMem(sizeof(struct CrunchMemList),
  1807.   MEMF_ANY)))
  1808.   {
  1809.     ml->cml_Next = fd->fd_MemList;
  1810.     ml->cml_MemoryRegion = reg;
  1811.     ml->cml_MemorySize = size;
  1812.     fd->fd_MemList = ml;
  1813.     return 0;
  1814.   }
  1815.  
  1816.   return CHKXERR_NOMEMORY;
  1817. }
  1818.  
  1819. /* Free memory from the memory list. */
  1820. static void FreeCrunchMemList(struct FileData *fd, APTR reg)
  1821. {
  1822.   struct CrunchMemList mc, *ml = &mc;
  1823.  
  1824.   if(fd->fd_Flags & CHECKXFLAG_NOFREEMEM)
  1825.     return;
  1826.  
  1827.   for(mc.cml_Next = fd->fd_MemList; ml; ml = ml->cml_Next)
  1828.   {
  1829.     if(ml->cml_Next->cml_MemoryRegion == reg)
  1830.     {
  1831.       struct CrunchMemList *m;
  1832.       m = ml->cml_Next;
  1833.       ml->cml_Next = m->cml_Next;
  1834.       FreeMem(m->cml_MemoryRegion, m->cml_MemorySize);
  1835.       FreeMem(m, sizeof(struct CrunchMemList));
  1836.     }
  1837.   }
  1838.  
  1839.   fd->fd_MemList = mc.cml_Next;
  1840. }
  1841.  
  1842. /* Save file, when SAVE option and file was crunched or linked. */
  1843. static LONG SaveUncrFile(struct FileData *fd, APTR buf, ULONG size)
  1844. {
  1845.   BPTR filefh, cd;
  1846.   LONG ret = 0, i = 0;
  1847.   UBYTE name[50];
  1848.   UBYTE nbuf[256];
  1849.  
  1850.   if(!(fd->fd_SaveDirL && (fd->fd_Flags & CHKXSAVEFLAGS)))
  1851.     return 0;
  1852.  
  1853.   SPrintF(fd, name, (fd->fd_LinkNum ? "%s.%ld" : "%s"), FilePart(fd->fd_Name),
  1854.   fd->fd_LinkNum);
  1855.  
  1856.   cd = CurrentDir(fd->fd_SaveDirL);
  1857.  
  1858.   while(!ret && name[i])
  1859.   {
  1860.     for(;name[i] && name[i] != '/'; ++i)
  1861.       nbuf[i] = name[i];
  1862.     if(name[i] == '/')
  1863.     {
  1864.       nbuf[i] = 0;
  1865.       if((filefh = Lock(nbuf, SHARED_LOCK)))
  1866.         UnLock(filefh);
  1867.       else
  1868.       {
  1869.         if((filefh = CreateDir(nbuf)))
  1870.           UnLock(filefh);
  1871.         else
  1872.           ret = CHKXERR_OPENERR;
  1873.       }
  1874.       nbuf[i] = name[i];
  1875.       ++i;
  1876.     }
  1877.   }
  1878.  
  1879.   if(!ret)
  1880.   {
  1881.     if((filefh = Open(name, MODE_NEWFILE)))
  1882.     {
  1883.       if(Write(filefh, buf, size) != size)
  1884.         ret = CHKXERR_WRITE;
  1885.       Close(filefh);
  1886.     }
  1887.     else
  1888.       ret = CHKXERR_OPENERR;
  1889.   }
  1890.  
  1891.   CurrentDir(cd);
  1892.  
  1893.   return ret;
  1894. }
  1895.  
  1896. static ASM(void) SPrintF_putfunc(REG(d0, UBYTE data), REG(a3, STRPTR *a))
  1897. {
  1898.   *((*a)++) = data;
  1899. }
  1900.  
  1901. static void SPrintF(struct FileData *fd, STRPTR buf, STRPTR format, ...)
  1902. {
  1903.   STRPTR buf2 = buf;
  1904.   RawDoFmt(format, (APTR) ((ULONG)&format+sizeof(STRPTR)),
  1905.   (void(*)()) SPrintF_putfunc, &buf2);
  1906. }
  1907.  
  1908. static ASM(void) KPutC(REG(d0, ULONG c), REG(a3, struct FileData *fd))
  1909. {
  1910.   RawPutChar(c);
  1911. }
  1912.  
  1913. static void KPrintf(struct FileData *fd, STRPTR fmt, ...)
  1914. {
  1915.   RawDoFmt(fmt, &fmt + 1, (void (*)()) KPutC, fd);
  1916. }
  1917.  
  1918. #ifdef __SASC
  1919.   #undef SysBase
  1920.   #define SysBase sysbase
  1921. #endif
  1922.  
  1923. static ASM(LONG) BreakHookCheckX(void)
  1924. {
  1925.   return (SetSignal(0L,0L) & SIGBREAKF_CTRL_C) ? 0 : XADPIF_OK;
  1926. }
  1927.  
  1928.